//
// Copyright (c) 2016-2019 Kris Jusiak (kris at jusiak dot net)
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
#include <cstdlib>
#include "benchmark.hpp"

struct e1 {};
struct e2 {};
struct e3 {};
struct e4 {};
struct e5 {};
struct e6 {};
struct e7 {};
struct e8 {};
struct e9 {};
struct e10 {};
struct e11 {};
struct e12 {};
struct e13 {};
struct e14 {};
struct e15 {};
struct e16 {};
struct e17 {};
struct e18 {};
struct e19 {};
struct e20 {};
struct e21 {};
struct e22 {};
struct e23 {};
struct e24 {};
struct e25 {};
struct e26 {};
struct e27 {};
struct e28 {};
struct e29 {};
struct e30 {};
struct e31 {};
struct e32 {};
struct e33 {};
struct e34 {};
struct e35 {};
struct e36 {};
struct e37 {};
struct e38 {};
struct e39 {};
struct e40 {};
struct e41 {};
struct e42 {};
struct e43 {};
struct e44 {};
struct e45 {};
struct e46 {};
struct e47 {};
struct e48 {};
struct e49 {};
struct e50 {};

struct c {
  enum class State : unsigned char {
    S1,
    S2,
    S3,
    S4,
    S5,
    S6,
    S7,
    S8,
    S9,
    S10,
    S11,
    S12,
    S13,
    S14,
    S15,
    S16,
    S17,
    S18,
    S19,
    S20,
    S21,
    S22,
    S23,
    S24,
    S25,
    S26,
    S27,
    S28,
    S29,
    S30,
    S31,
    S32,
    S33,
    S34,
    S35,
    S36,
    S37,
    S38,
    S39,
    S40,
    S41,
    S42,
    S43,
    S44,
    S45,
    S46,
    S47,
    S48,
    S49,
    S50
  } state;

  bool guard() { return true; }
  void action() {}

  void handle(const e1&) {
    switch (state) {
      default:
        break;
      case State::S1:
        if (guard()) {
          action();
          state = State::S2;
        }
        break;
    }
  }

  void handle(const e2&) {
    switch (state) {
      default:
        break;
      case State::S2:
        if (guard()) {
          action();
          state = State::S3;
        }
        break;
    }
  }

  void handle(const e3&) {
    switch (state) {
      default:
        break;
      case State::S3:
        if (guard()) {
          action();
          state = State::S4;
        }
        break;
    }
  }

  void handle(const e4&) {
    switch (state) {
      default:
        break;
      case State::S4:
        if (guard()) {
          action();
          state = State::S5;
        }
        break;
    }
  }

  void handle(const e5&) {
    switch (state) {
      default:
        break;
      case State::S5:
        if (guard()) {
          action();
          state = State::S6;
        }
        break;
    }
  }

  void handle(const e6&) {
    switch (state) {
      default:
        break;
      case State::S6:
        if (guard()) {
          action();
          state = State::S7;
        }
        break;
    }
  }

  void handle(const e7&) {
    switch (state) {
      default:
        break;
      case State::S7:
        if (guard()) {
          action();
          state = State::S8;
        }
        break;
    }
  }

  void handle(const e8&) {
    switch (state) {
      default:
        break;
      case State::S8:
        if (guard()) {
          action();
          state = State::S9;
        }
        break;
    }
  }

  void handle(const e9&) {
    switch (state) {
      default:
        break;
      case State::S9:
        if (guard()) {
          action();
          state = State::S10;
        }
        break;
    }
  }

  void handle(const e10&) {
    switch (state) {
      default:
        break;
      case State::S10:
        if (guard()) {
          action();
          state = State::S11;
        }
        break;
    }
  }

  void handle(const e11&) {
    switch (state) {
      default:
        break;
      case State::S11:
        if (guard()) {
          action();
          state = State::S12;
        }
        break;
    }
  }

  void handle(const e12&) {
    switch (state) {
      default:
        break;
      case State::S12:
        if (guard()) {
          action();
          state = State::S13;
        }
        break;
    }
  }

  void handle(const e13&) {
    switch (state) {
      default:
        break;
      case State::S13:
        if (guard()) {
          action();
          state = State::S14;
        }
        break;
    }
  }

  void handle(const e14&) {
    switch (state) {
      default:
        break;
      case State::S14:
        if (guard()) {
          action();
          state = State::S15;
        }
        break;
    }
  }

  void handle(const e15&) {
    switch (state) {
      default:
        break;
      case State::S15:
        if (guard()) {
          action();
          state = State::S16;
        }
        break;
    }
  }

  void handle(const e16&) {
    switch (state) {
      default:
        break;
      case State::S16:
        if (guard()) {
          action();
          state = State::S17;
        }
        break;
    }
  }

  void handle(const e17&) {
    switch (state) {
      default:
        break;
      case State::S17:
        if (guard()) {
          action();
          state = State::S18;
        }
        break;
    }
  }

  void handle(const e18&) {
    switch (state) {
      default:
        break;
      case State::S18:
        if (guard()) {
          action();
          state = State::S19;
        }
        break;
    }
  }

  void handle(const e19&) {
    switch (state) {
      default:
        break;
      case State::S19:
        if (guard()) {
          action();
          state = State::S20;
        }
        break;
    }
  }

  void handle(const e20&) {
    switch (state) {
      default:
        break;
      case State::S20:
        if (guard()) {
          action();
          state = State::S21;
        }
        break;
    }
  }

  void handle(const e21&) {
    switch (state) {
      default:
        break;
      case State::S21:
        if (guard()) {
          action();
          state = State::S22;
        }
        break;
    }
  }

  void handle(const e22&) {
    switch (state) {
      default:
        break;
      case State::S22:
        if (guard()) {
          action();
          state = State::S23;
        }
        break;
    }
  }

  void handle(const e23&) {
    switch (state) {
      default:
        break;
      case State::S23:
        if (guard()) {
          action();
          state = State::S24;
        }
        break;
    }
  }

  void handle(const e24&) {
    switch (state) {
      default:
        break;
      case State::S24:
        if (guard()) {
          action();
          state = State::S25;
        }
        break;
    }
  }

  void handle(const e25&) {
    switch (state) {
      default:
        break;
      case State::S25:
        if (guard()) {
          action();
          state = State::S26;
        }
        break;
    }
  }

  void handle(const e26&) {
    switch (state) {
      default:
        break;
      case State::S26:
        if (guard()) {
          action();
          state = State::S27;
        }
        break;
    }
  }

  void handle(const e27&) {
    switch (state) {
      default:
        break;
      case State::S27:
        if (guard()) {
          action();
          state = State::S28;
        }
        break;
    }
  }

  void handle(const e28&) {
    switch (state) {
      default:
        break;
      case State::S28:
        if (guard()) {
          action();
          state = State::S29;
        }
        break;
    }
  }

  void handle(const e29&) {
    switch (state) {
      default:
        break;
      case State::S29:
        if (guard()) {
          action();
          state = State::S30;
        }
        break;
    }
  }

  void handle(const e30&) {
    switch (state) {
      default:
        break;
      case State::S30:
        if (guard()) {
          action();
          state = State::S31;
        }
        break;
    }
  }

  void handle(const e31&) {
    switch (state) {
      default:
        break;
      case State::S31:
        if (guard()) {
          action();
          state = State::S32;
        }
        break;
    }
  }

  void handle(const e32&) {
    switch (state) {
      default:
        break;
      case State::S32:
        if (guard()) {
          action();
          state = State::S33;
        }
        break;
    }
  }

  void handle(const e33&) {
    switch (state) {
      default:
        break;
      case State::S33:
        if (guard()) {
          action();
          state = State::S34;
        }
        break;
    }
  }

  void handle(const e34&) {
    switch (state) {
      default:
        break;
      case State::S34:
        if (guard()) {
          action();
          state = State::S35;
        }
        break;
    }
  }

  void handle(const e35&) {
    switch (state) {
      default:
        break;
      case State::S35:
        if (guard()) {
          action();
          state = State::S36;
        }
        break;
    }
  }

  void handle(const e36&) {
    switch (state) {
      default:
        break;
      case State::S36:
        if (guard()) {
          action();
          state = State::S37;
        }
        break;
    }
  }

  void handle(const e37&) {
    switch (state) {
      default:
        break;
      case State::S37:
        if (guard()) {
          action();
          state = State::S38;
        }
        break;
    }
  }

  void handle(const e38&) {
    switch (state) {
      default:
        break;
      case State::S38:
        if (guard()) {
          action();
          state = State::S39;
        }
        break;
    }
  }

  void handle(const e39&) {
    switch (state) {
      default:
        break;
      case State::S39:
        if (guard()) {
          action();
          state = State::S40;
        }
        break;
    }
  }

  void handle(const e40&) {
    switch (state) {
      default:
        break;
      case State::S40:
        if (guard()) {
          action();
          state = State::S41;
        }
        break;
    }
  }

  void handle(const e41&) {
    switch (state) {
      default:
        break;
      case State::S41:
        if (guard()) {
          action();
          state = State::S42;
        }
        break;
    }
  }

  void handle(const e42&) {
    switch (state) {
      default:
        break;
      case State::S42:
        if (guard()) {
          action();
          state = State::S43;
        }
        break;
    }
  }

  void handle(const e43&) {
    switch (state) {
      default:
        break;
      case State::S43:
        if (guard()) {
          action();
          state = State::S44;
        }
        break;
    }
  }

  void handle(const e44&) {
    switch (state) {
      default:
        break;
      case State::S44:
        if (guard()) {
          action();
          state = State::S45;
        }
        break;
    }
  }

  void handle(const e45&) {
    switch (state) {
      default:
        break;
      case State::S45:
        if (guard()) {
          action();
          state = State::S46;
        }
        break;
    }
  }

  void handle(const e46&) {
    switch (state) {
      default:
        break;
      case State::S46:
        if (guard()) {
          action();
          state = State::S47;
        }
        break;
    }
  }

  void handle(const e47&) {
    switch (state) {
      default:
        break;
      case State::S47:
        if (guard()) {
          action();
          state = State::S48;
        }
        break;
    }
  }

  void handle(const e48&) {
    switch (state) {
      default:
        break;
      case State::S48:
        if (guard()) {
          action();
          state = State::S49;
        }
        break;
    }
  }

  void handle(const e49&) {
    switch (state) {
      default:
        break;
      case State::S49:
        if (guard()) {
          action();
          state = State::S50;
        }
        break;
    }
  }

  void handle(const e50&) {
    switch (state) {
      default:
        break;
      case State::S50:
        if (guard()) {
          action();
          state = State::S1;
        }
        break;
    }
  }
};

int main() {
  c sm;

  benchmark_execution_speed([&] {
    for (auto i = 0; i < 1'000'000; ++i) {
      if (rand() % 2) sm.handle(e1());
      if (rand() % 2) sm.handle(e2());
      if (rand() % 2) sm.handle(e3());
      if (rand() % 2) sm.handle(e4());
      if (rand() % 2) sm.handle(e5());
      if (rand() % 2) sm.handle(e6());
      if (rand() % 2) sm.handle(e7());
      if (rand() % 2) sm.handle(e8());
      if (rand() % 2) sm.handle(e9());
      if (rand() % 2) sm.handle(e10());
      if (rand() % 2) sm.handle(e11());
      if (rand() % 2) sm.handle(e12());
      if (rand() % 2) sm.handle(e13());
      if (rand() % 2) sm.handle(e14());
      if (rand() % 2) sm.handle(e15());
      if (rand() % 2) sm.handle(e16());
      if (rand() % 2) sm.handle(e17());
      if (rand() % 2) sm.handle(e18());
      if (rand() % 2) sm.handle(e19());
      if (rand() % 2) sm.handle(e20());
      if (rand() % 2) sm.handle(e21());
      if (rand() % 2) sm.handle(e22());
      if (rand() % 2) sm.handle(e23());
      if (rand() % 2) sm.handle(e24());
      if (rand() % 2) sm.handle(e25());
      if (rand() % 2) sm.handle(e26());
      if (rand() % 2) sm.handle(e27());
      if (rand() % 2) sm.handle(e28());
      if (rand() % 2) sm.handle(e29());
      if (rand() % 2) sm.handle(e30());
      if (rand() % 2) sm.handle(e31());
      if (rand() % 2) sm.handle(e32());
      if (rand() % 2) sm.handle(e33());
      if (rand() % 2) sm.handle(e34());
      if (rand() % 2) sm.handle(e35());
      if (rand() % 2) sm.handle(e36());
      if (rand() % 2) sm.handle(e37());
      if (rand() % 2) sm.handle(e38());
      if (rand() % 2) sm.handle(e39());
      if (rand() % 2) sm.handle(e40());
      if (rand() % 2) sm.handle(e41());
      if (rand() % 2) sm.handle(e42());
      if (rand() % 2) sm.handle(e43());
      if (rand() % 2) sm.handle(e44());
      if (rand() % 2) sm.handle(e45());
      if (rand() % 2) sm.handle(e46());
      if (rand() % 2) sm.handle(e47());
      if (rand() % 2) sm.handle(e48());
      if (rand() % 2) sm.handle(e49());
      if (rand() % 2) sm.handle(e50());
    }
  });
  benchmark_memory_usage(sm);
}
